using System;
using System.Linq;
using FluentNHibernate;
using FluentNHibernate.Automapping;
using FluentNHibernate.Conventions;
using good1.Core;
using good1.Core.Attributes;
using good1.Data.NHibernateMaps.Conventions;
using SharpArch.Core;
using SharpArch.Core.DomainModel;
using SharpArch.Data.NHibernate.FluentNHibernate;

namespace good1.Data.NHibernateMaps
{
    public class AutoPersistenceModelGenerator : IAutoPersistenceModelGenerator
    {
        public AutoPersistenceModel Generate()
        {
            var mappings = new AutoPersistenceModel();
            mappings.AddEntityAssembly(typeof(User).Assembly).Where(GetAutoMappingFilter);
            mappings.Conventions.Setup(GetConventions());
            mappings.Setup(GetSetup());
            mappings.IgnoreBase<Entity>();
            mappings.IgnoreBase(typeof(EntityWithTypedId<>));
           
            mappings.UseOverridesFromAssemblyOf<AutoPersistenceModelGenerator>();
            return mappings;
        }

        private Action<AutoMappingExpressions> GetSetup()
        {
            return c =>
            {
                c.FindIdentity = type => type.Name == "Id";
                //two below are custome additions.
                c.IsComponentType = type => type == typeof (LatLng);
                c.GetComponentColumnPrefix = type => type.Name + "_";
             };
        }

        private Action<IConventionFinder> GetConventions()
        {
            return c =>
            {
                c.Add<PrimaryKeyConvention>();
                c.Add<ReferenceConvention>();
                c.Add<HasManyConvention>();
                c.Add<TableNameConvention>();

                //new conventions below for manytomany
                c.Add<HasManyToManyConvention>();
                c.Add<CustomManyToManyTableNameConvention>();
                c.Add<CustomForeignKeyConvention>();
            };
        }

        /// <summary>
        /// Provides a filter for only including types which inherit from the IEntityWithTypedId interface.
        /// </summary>
        private static bool GetAutoMappingFilter(Type t)
        {
            return t.GetInterfaces().Any(x =>
                 x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEntityWithTypedId<>));
        }


        //inspired by http://groups.google.com/group/sharp-architecture/browse_thread/thread/b639b66a21ddc057/137967bf03a47b3b?lnk=gst&q=subclass#137967bf03a47b3b
        //first brought in because we will not be using auto persitance for User as it requires subclasses with class per hierarchy
       // will not be needed for User if we get override working, but could be useful for some other exceptions.
        private static bool CheckPeristance(Type t) { 
            var attributes = t.GetCustomAttributes(typeof (DoNotAutoPersistAttribute), true); 
            Check.Ensure(attributes.Length<=1, "The number of DoNotAutoPersistAttribute can only be less than or equal to 1"); 
            if (attributes.Length == 0) 
                return false;
            var persist = attributes[0] as DoNotAutoPersistAttribute; 
            return persist == null; 
        } 

    }
}
